package 反射;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

//对任意的一个Object实例，只要我们获取了它的Class，就可以获取它的一切信息。
//
//我们先看看如何通过Class实例获取字段信息。Class类提供了以下几个方法来获取字段：
//
//Field getField(name)：根据字段名获取某个public的field（包括父类）
//Field getDeclaredField(name)：根据字段名获取当前类的某个field（不包括父类）
//Field[] getFields()：获取所有public的field（包括父类）
//Field[] getDeclaredFields()：获取当前类的所有field（不包括父类）
//我们来看一下示例代码：

// reflection
/*import java.util.Arrays;
public class 访问字段 {
    public static void main(String[] args) throws Exception {
    	 byte[] value;
    	Field f = String.class.getDeclaredField("value");
    	System.out.println(f.getName()); // "value"
    	System.out.println(f.getType()); // class [B 表示byte[]类型
    	int m = f.getModifiers();
    	Class mf=Modifier.class;
    	Field [] mfield=mf.getFields();
    	for (Field fie:mfield) {
    		System.out.println(fie);
    	}

//AVA 反射机制中，Field的getModifiers()方法返回int类型值表示该字段的修饰符。
//其中，该修饰符是java.lang.reflect.Modifier的静态属性。
//对应表如下：
//PUBLIC: 1
//PRIVATE: 2
//PROTECTED: 4
//STATIC: 8
//FINAL: 16
//SYNCHRONIZED: 32
//VOLATILE: 64
//TRANSIENT: 128
//NATIVE: 256
//INTERFACE: 512
//ABSTRACT: 1024
//STRICT: 2048
    	
//    	System.out.println(Modifier.isFinal(m)); // true
//    	System.out.println(Modifier.isPublic(m)); // false
//    	System.out.println(Modifier.isProtected(m)); // false
//    	System.out.println(Modifier.isPrivate(m)); // true
//    	System.out.println(Modifier.isStatic(m)); // false
//    	
        Class stdClass = Student3.class;
        Field [] std=stdClass.getFields();
        System.out.println(Arrays.toString(std));//[public int 反射.Student.score, public java.lang.String 反射.Person.name]
        // 获取public字段"score":
        Field field=stdClass.getField("score");
        System.out.println(field);//public int 反射.Student.score
        
        System.out.println("3"+field.getName());//score
        System.out.println(stdClass.getField("score"));//public int 反射.Student.score
        // 获取继承的public字段"name":
        System.out.println(stdClass.getField("name"));//public java.lang.String 反射.Person.name
        // 获取private字段"grade":
        System.out.println(stdClass.getDeclaredField("grade"));//private int 反射.Student.grade
    }

}

class Student3 extends Person3 {
    public int score;
    private int grade;
}

class Person3 {
    public String name;
}*/

//一个Field对象包含了一个字段的所有信息：
//
//getName()：返回字段名称，例如，"name"；
//getType()：返回字段类型，也是一个Class实例，例如，String.class；
//getModifiers()：返回字段的修饰符，它是一个int，不同的bit表示不同的含义。
//以String类的value字段为例，它的定义是：
//
//public final class String {
//    private final byte[] value;
//}
//我们用反射获取该字段的信息，代码如下：
//
//Field f = String.class.getDeclaredField("value");
//f.getName(); // "value"
//f.getType(); // class [B 表示byte[]类型
//int m = f.getModifiers();
//Modifier.isFinal(m); // true
//Modifier.isPublic(m); // false
//Modifier.isProtected(m); // false
//Modifier.isPrivate(m); // true
//Modifier.isStatic(m); // false

//《获取字段值》
//利用反射拿到字段的一个Field实例只是第一步，我们还可以拿到一个实例对应的该字段的值。
//例如，对于一个Person实例，我们可以先拿到name字段对应的Field，再获取这个实例的name字段的值：

// reflection

/*public class 访问字段 {

    public static void main(String[] args) throws Exception {
        Object p = new Person3("Xiao Ming");
        Class c = p.getClass();//通过实例变量p(class)，提供的getClass()方法获取class(p)的Class实例c
//        Field f = c.getDeclaredField("name");
        Field f = c.getField("name");
        f.setAccessible(true);
        Object value = f.get(p);
        System.out.println(value); // "Xiao Ming"
    }
}

class Person3 {
//    private String name;//通过getDeclaredField(name),访问根据字段名获取当前类的某个field（不包括父类）
    public String name;//通过getField(name)访问,根据字段名获取某个public的field（包括父类）

    public Person3(String name) {
        this.name = name;
    }
}*/

//上述代码先获取Class实例，再获取Field实例，然后，用Field.get(Object)获取指定实例的指定字段的值。

//
//运行代码，如果不出意外，会得到一个IllegalAccessException，这是因为name被定义为一个private字段，正常情况下，Main类无法访问Person类的private字段。
//要修复错误，可以将private改为public，或者，在调用Object value = f.get(p);前，先写一句：
//
//f.setAccessible(true);
//调用Field.setAccessible(true)的意思是，别管这个字段是不是public，一律允许访问。
//
//可以试着加上上述语句，再运行代码，就可以打印出private字段的值。
//
//有童鞋会问：如果使用反射可以获取private字段的值，那么类的封装还有什么意义？
//
//答案是正常情况下，我们总是通过p.name来访问Person的name字段，编译器会根据public、protected和private决定是否允许访问字段，这样就达到了数据封装的目的。
//
//而反射是一种非常规的用法，使用反射，首先代码非常繁琐，其次，它更多地是给工具或者底层框架来使用，目的是在不知道目标实例任何信息的情况下，获取特定字段的值。
//
//此外，setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager，那么它会根据规则进行检查，有可能阻止setAccessible(true)。
//例如，某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true)，这样可以保证JVM核心库的安全。

//《设置字段值》
//通过Field实例既然可以获取到指定实例的字段值，自然也可以设置字段的值。
//设置字段值是通过Field.set(Object, Object)实现的，其中第一个Object参数是指定的实例，第二个Object参数是待修改的值。示例代码如下：

// reflection

/*public class 访问字段 {

    public static void main(String[] args) throws Exception {
        Person p = new Person("Xiao Ming");
        System.out.println(p.getName()); // "Xiao Ming"

//        Class c = Person.class;//与下相同
        Class c =p.getClass();

        Field f = c.getDeclaredField("name");//可对private或protected字段访问
//        Field f =c.getField("name");//需将name设为public方可访问

        f.setAccessible(true);
        f.set(p, "Xiao Hong");
        System.out.println(p.getName()); // "Xiao Hong"
    }
}

class Person {
    protected String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }
}*/

//运行上述代码，打印的name字段从Xiao Ming变成了Xiao Hong，说明通过反射可以直接修改字段的值。
//同样的，修改非public字段，需要首先调用setAccessible(true)。

//以下四种方法在Class类可以返回关于字段的 Field 对象。
//
//Field[] getFields() 方法返回所有可访问的公共字段在类中声明或继承自超类。
//Field[] getDeclaredFields() 返回所有字段只出现在类的声明中(不是从继承的字段)。
//Field getField(String name) 通过字段名获取 Field 对象。（包括父类）
//Field getDeclaredField(String name) 通过字段名获取 Field 对象。（不包括父类）

/*import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;

class MySuperClass {
	public int super_id = -1;
	public String super_name = "Unknown";

}

class MyClass extends MySuperClass {
	public int id = -1;
	public String name = "Unknown";

}

public class 访问字段 {
	public static void main(String[] args) {
		Class<MyClass> c = MyClass.class;
//		var c=MyClass.class;//亦可
		
		// Print declared fields
		ArrayList<String> fieldsDesciption = getDeclaredFieldsList(c);

		System.out.println("Declared Fields for " + c.getName());
		for (String desc : fieldsDesciption) {
			System.out.println("1"+desc);
		}

		fieldsDesciption = getFieldsList(c);

		System.out.println("\nAccessible Fields for " + c.getName());
		for (String desc : fieldsDesciption) {
			System.out.println("2"+desc);
		}
	}

	public static ArrayList<String> getFieldsList(Class c) {//包括父类及其当前类
		Field[] fields = c.getFields();
		ArrayList<String> fieldsList = getFieldsDesciption(fields);
		return fieldsList;
	}

	public static ArrayList<String> getDeclaredFieldsList(Class c) {//当前类，不包括父类
		Field[] fields = c.getDeclaredFields();
		ArrayList<String> fieldsList = getFieldsDesciption(fields);
		return fieldsList;
	}

	public static ArrayList<String> getFieldsDesciption(Field[] fields) {
		ArrayList<String> fieldList = new ArrayList<>();

		for (Field f : fields) {
			int mod = f.getModifiers() & Modifier.fieldModifiers();
//			System.out.println(Integer.toString(f.getModifiers(),2)
//					+" "+Integer.toString(Modifier.fieldModifiers(),2)
//					+" "+Integer.toString(mod,2));
			String modifiers = Modifier.toString(mod);

			Class<?> type = f.getType();
			String typeName = type.getSimpleName();

			String fieldName = f.getName();

			fieldList.add(modifiers + "  " + typeName + "  " + fieldName);
		}

		return fieldList;
	}
}*/

//《Java Class.getField()/getDeclaredField()返回成员变量》
//
//-Class.getField()返回已加载类声明的所有public成员变量的Field对象，包括从父类继承过来的成员变量，参数name指定成员变量的名称。
//
//-Class.getDeclaredField()返回当前类所有成员变量。
//
//《定义》
//Field getField(String name)
//Field getDeclaredField(String name)
//《源码》
//public Field getDeclaredField(String name) throws NoSuchFieldException,SecurityException{
//    checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader());
//    Field field = searchFields(privateGetDeclaredFields(false), name);
//    if (field == null) {
//        throw new NoSuchFieldException(name);
//    }
//    return field;
//}
//Private Field getField0(String name) throws NoSuchFieldException {  
//       Field res = null;  
//       // Search declared public fields  
//       if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {  
//           return res;  
//       }  
//...... 
//getField其实调用的是getField0，他们最后都调用了searchFields，不过getDeclaredField传入的是privateGetDeclaredFields(false), 
//getField传入的是privateGetDeclaredFields(true)。
//
//例子
//package cn.com.vo;
import java.lang.reflect.Constructor;
//import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Father {
    public String name = "父亲";
    public String sex = "男";
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

class Son extends Father {
    //public String name;
    public int age = 20;
}

public class 访问字段 {

    public static void main(String[] args) {
        try {
            //类的动态加载
            Class c = Class.forName("反射.Son"); //方式一
            Son vo = (Son) c.newInstance();

            Field f = c.getField("name");
            System.out.println(f.get(vo));

            //注意：下段代码会报错，
            /*Field f2=c.getDeclaredField("name");
    System.out.println(f2.get(vo));*/
        } catch(ClassNotFoundException e) {
            e.printStackTrace();
        } catch(SecurityException e) {
            e.printStackTrace();
        } catch(NoSuchFieldException e) {
            e.printStackTrace();
        } catch(InstantiationException e) {
            e.printStackTrace();
        } catch(IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
//总结
//1. getDeclaredField是可以获取一个类本身的所有字段. getField只能获取类及其父类的public 字段. 
//2. 如果想要获取父类的所有成员变量（主要是为了拿到私有成员变量，只想获取公有成员变量可以直接使用getField）,可以通过取得当前类的父类
//的class对象再调用getDeclaredField方法。

